/**
 * \brief 从摄像头获取YUV NV12
 * \note 播放YUV NV12的命令
 *       ffplay -f rawvideo -pix_fmt nv12 -video_size 1280x720 test.nv12
 */

#include "module.h"
#include "module_yuvin.h"
#include <string.h> // memcpy
#include <stdio.h>  // printf fflush

#define EPERM 1 /* Operation not permitted */
#define pr_info printf
#define MDATA_LEN (2 * 1024 * 1024) // 视频1280x720 NV12 1.5字节每像素一帧1,382,400字节
static unsigned char mdata[MDATA_LEN];
int yuvmdatalen = 0; // 既作为长度，又作为消费者生产者的锁
static struct module *target = NULL;

int yuvin_module_register()
{
    yuvmdatalen = 0; // 释放锁

    return 0;
}

/**
 * \param flag: 0代表一帧开始，1代表一帧结束
 */
int yuvin_module_putdata(char *data, int len, int flag)
{
    static int totallen;

    /* 被调用者保证此时已得到锁才调用了此函数 */

    if (!data || len > MDATA_LEN)
        return -EPERM;

    if (flag == 0)
        totallen = 0;

    memcpy(mdata + totallen, data, len); // 赋值数据（一帧要分多次赋予）
    totallen += len;

    if (flag == 1)
        yuvmdatalen = totallen; // 赋值长度并上锁

//    pr_info("yuv %d %d, ", totallen, yuvmdatalen);
//    fflush(stdout);

    return 0;
}

static int module_init(void)
{
    if (target)
        target->init();

    return 0;
}

static int module_start(void *param)
{
    start_param_t sparam = {"test.nv12", AVTYPE_H264};

    if (target)
        target->start(&sparam);

    return 0;
}

static int module_run(void)
{
    if (target)
        target->run();

    if (!yuvmdatalen) // 如果没有数据，未获取到锁
        return 0;
    if (target)
        target->putdata(mdata, yuvmdatalen, 0);

    yuvmdatalen = 0; // 释放锁

    return 0;
}

static int module_stop(void)
{
    if (target)
        target->stop();

    return 0;
}

static int module_exit(void)
{
    if (target)
        target->exit();

    return 0;
}

static int module_settarget(void *mtarget)
{
    target = (struct module *)mtarget;

    return 0;
}

static int module_putdata(void *data, int len, int flag)
{
    return 0;
}

struct module g_module_yuvin = {
    "yuvin", module_init,
    module_start, module_run,
    module_stop, module_exit,
    module_settarget, module_putdata
};
